/*
	UART Layer

	This module defines the Uart layer for both Atmega1280 and Atmega128 MCU's

	Use the function hooks to utilise all the advanved features
*/

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include "globals.h"
#include "layer_uart.h"
#include "buffer.h"
#include "bikirom-ints.h"
#include "string.h"

// ---------------------------------------------------------------------
// Macros
#ifdef atmega1280
#define UART_COUNT	4
#else
#define UART_COUNT	2
#endif
#define UART_TIMEOUT 0x200

// ---------------------------------------------------------------------
// Typedefs
typedef struct _typUart {
	unsigned char	*rxBuf;			/* Pointer to buffer to store Rx Data */
	unsigned short	rxLength;		/* Length of the buffer */
	volatile unsigned short	rxBytes;		/* Bytes in the recieve buffer */
	volatile unsigned short	rxNotify;		/* Number of bytes to notify on */
	_uart_recieve	uart_recieve;	/* Function callback */
	cBuffer			txBuffer;		/* Transmit Buffer */
	enum _eExtInts	eRtsInt;		/* RTS Interrupt */
} _typUartRx;

typedef struct _typUartVars {
	struct _typUart	typUarts[UART_COUNT];	/* Uart Buffers */

} _typUartVars;

typedef struct _typUartRegs {
/*	volatile unsigned char	*UCSRXA;
	volatile unsigned char	*UCSRXB;
	volatile unsigned char	*UBRRXL;
	volatile unsigned char	*UDRX;*/
	vpIntHandler	vpRts;
} _typUartRegs;

typedef void (*vpfEnable)(uint8_t bEnable);

// ---------------------------------------------------------------------
// Private Functions
void	uart_set_baud		(uint8_t nUart, u32 baudrate);
void	uart0_signal_rts	(unsigned char state);
void	uart1_signal_rts	(unsigned char state);
void	uart2_signal_rts	(unsigned char state);
void	uart3_signal_rts	(unsigned char state);
//__attribute__((naked)) 
__inline__ static void	uart_recieve		(uint8_t nUart, uint8_t c);

// ---------------------------------------------------------------------
// Static Varialbes
struct _typUartVars	typVars;	/* Local Varialbes for Uarts */
static vpfEnable	enable_tx[UART_COUNT] =
{
	&uart_enable_tx_0,
	&uart_enable_tx_1,
#ifdef atmega1280
	&uart_enable_tx_2,
	&uart_enable_tx_3
#endif
};
/*static _typUartRegs	typRegs[] =
{
	{&UCSR0A, &UCSR0B, &UBRR0L, &UDR0, &uart0_signal_rts},	
	{&UCSR1A, &UCSR1B, &UBRR1L, &UDR1, &uart1_signal_rts},
#if UART_COUNT > 2
	{&UCSR2A, &UCSR2B, &UBRR2L, &UDR2, &uart2_signal_rts},
#endif
#if UART_COUNT > 3
	{&UCSR3A, &UCSR3B, &UBRR3L, &UDR3, &uart3_signal_rts},
#endif
};*/
static _typUartRegs	typRegs[] =
{
	{&uart0_signal_rts},	
	{&uart1_signal_rts},
#ifdef atmega1280
	{&uart2_signal_rts},
	{&uart3_signal_rts},
#endif
};

// ---------------------------------------------------------------------
// Functions Bodies
unsigned char	uart_init		(uint8_t nUart, unsigned long nBaud, _uart_recieve uart_recieve,
								 unsigned char* uchTxBuffer, u16 nTxLength,
								 unsigned char* uchRxBuffer, u16 nRxLength,
								 enum _eExtInts eRtsInt)
{
	// Rx Initialisation
	typVars.typUarts[nUart].rxBuf = uchRxBuffer;
	typVars.typUarts[nUart].rxLength = nRxLength;
	typVars.typUarts[nUart].rxBytes = 0;
	typVars.typUarts[nUart].rxNotify = 1;
	typVars.typUarts[nUart].uart_recieve = uart_recieve;

	// Tx Initialisation
	typVars.typUarts[nUart].eRtsInt = eRtsInt;
	bufferInit(&typVars.typUarts[nUart].txBuffer, uchTxBuffer, nTxLength);

	// Set the bause
	uart_set_baud(nUart, nBaud);

		// Rts Handler
	if (eRtsInt != eIntNone)
	{
		// Attach the interrupt
		int_attach(eRtsInt, eIntCtrlAny, typRegs[nUart].vpRts);
		// Trigger a state change (enforce original state)
		int_trigger(eRtsInt);
	}

	// Enable the Tx and Rx
	switch (nUart)
	{
	case 0:
		UCSR0B |= (unsigned char)(BV(TXEN0) | BV(RXEN0));
		uart_enable_rx_0(1);
		break;
	case 1:
		UCSR1B |= (unsigned char)(BV(TXEN1) | BV(RXEN1));
		uart_enable_rx_1(1);
		break;
#ifdef atmega1280
	case 2:
		UCSR2B |= (unsigned char)(BV(TXEN2) | BV(RXEN2));
		uart_enable_rx_2(1);
		break;
	case 3:
		UCSR3B |= (unsigned char)(BV(TXEN3) | BV(RXEN3));
		uart_enable_rx_3(1);
		break;
#endif
	}

	// Enable Interrupts
	sei();
	
	return TRUE;
}

//------------------------------------------------------------------------------------------------
// UART 0
//
// Enable the Rx
void			uart_enable_rx_0 (uint8_t bEnable)
{
	if (bEnable)
	{
		UCSR0B |= (unsigned char)BV(RXCIE0);
	}
	else
	{
		UCSR0B &= (unsigned char)~(BV(RXCIE0));
	}
}

void	uart_send_byte_unbuffered_0 (uint8_t data)
{
	UDR0 = data;
}

/* returns -1 for failure */
short	uart_get_byte_0			(void)
{
	unsigned short timeout = UART_TIMEOUT;

	do
	{
		if (UCSR0A & BV(RXC0))
		{
			return UDR0;
		}
		else
		{
			wdt_reset();
		}	

	} while (--timeout);

	return -1;
}

// Enable the Tx
void			uart_enable_tx_0	(uint8_t bEnable)
{
	if (bEnable 
	&& typVars.typUarts[0].txBuffer.datalength)
	{
		if (bEnable == 0x2 || typVars.typUarts[0].eRtsInt == eIntNone )
		{
			UCSR0B |= (unsigned char)BV(UDRIE0);
		}
		else
		{
			// Trigger Interrupt state
			int_trigger(typVars.typUarts[0].eRtsInt);
		}
	}
	else
	{
		UCSR0B &= (unsigned char)~(BV(UDRIE0));
	}
}

//------------------------------------------------------------------------------------------------
// UART 1
//
// Enable the Rx
void			uart_enable_rx_1 (uint8_t bEnable)
{
	if (bEnable)
	{
		UCSR1B |= (unsigned char)BV(RXCIE1);
	}
	else
	{
		UCSR1B &= (unsigned char)~(BV(RXCIE1));
	}
}

void	uart_send_byte_unbuffered_1 (uint8_t data)
{
	UDR1 = data;
}

/* returns -1 for failure */
short	uart_get_byte_1			(void)
{
	unsigned short timeout = UART_TIMEOUT;

	do
	{
		if (UCSR1A & BV(RXC1))
		{
			return UDR1;
		}
		else
		{
			wdt_reset();
		}	

	} while (--timeout);

	return -1;
}

// Enable the Tx
void			uart_enable_tx_1	(uint8_t bEnable)
{
	if (bEnable 
	&& typVars.typUarts[1].txBuffer.datalength)
	{
		if (bEnable == 0x2 || typVars.typUarts[1].eRtsInt == eIntNone )
		{
			UCSR1B |= (unsigned char)BV(UDRIE1);
		}
		else
		{
			// Trigger Interrupt state
			int_trigger(typVars.typUarts[1].eRtsInt);
		}
	}
	else
	{
		UCSR1B &= (unsigned char)~(BV(UDRIE1));
	}
}

#ifdef atmega1280
//------------------------------------------------------------------------------------------------
// UART 2
//
// Enable the Rx
void			uart_enable_rx_2 (uint8_t bEnable)
{
	if (bEnable)
	{
		UCSR2B |= (unsigned char)BV(RXCIE2);
	}
	else
	{
		UCSR2B &= (unsigned char)~(BV(RXCIE2));
	}
}

void	uart_send_byte_unbuffered_2 (uint8_t data)
{
	UDR2 = data;
}

/* returns -1 for failure */
short	uart_get_byte_2			(void)
{
	unsigned short timeout = UART_TIMEOUT;

	do
	{
		if (UCSR2A & BV(RXC2))
		{
			return UDR2;
		}
		else
		{
			wdt_reset();
		}	

	} while (--timeout);

	return -1;
}

// Enable the Tx
void			uart_enable_tx_2	(uint8_t bEnable)
{
	if (bEnable 
	&& typVars.typUarts[2].txBuffer.datalength)
	{
		if (bEnable == 0x2 || typVars.typUarts[2].eRtsInt == eIntNone )
		{
			UCSR2B |= (unsigned char)BV(UDRIE2);
		}
		else
		{
			// Trigger Interrupt state
			int_trigger(typVars.typUarts[2].eRtsInt);
		}
	}
	else
	{
		UCSR2B &= (unsigned char)~(BV(UDRIE2));
	}
}

//------------------------------------------------------------------------------------------------
// UART 3
//
// Enable the Rx
void			uart_enable_rx_3 (uint8_t bEnable)
{
	if (bEnable)
	{
		UCSR3B |= (unsigned char)BV(RXCIE3);
	}
	else
	{
		UCSR3B &= (unsigned char)~(BV(RXCIE3));
	}
}

void	uart_send_byte_unbuffered_3 (uint8_t data)
{
	UDR3 = data;
}

/* returns -1 for failure */
short	uart_get_byte_3			(void)
{
	unsigned short timeout = UART_TIMEOUT;

	do
	{
		if (UCSR3A & BV(RXC3))
		{
			return UDR3;
		}
		else
		{
			wdt_reset();
		}	

	} while (--timeout);

	return -1;
}

// Enable the Tx
void			uart_enable_tx_3	(uint8_t bEnable)
{
	if (bEnable 
	&& typVars.typUarts[3].txBuffer.datalength)
	{
		if (bEnable == 0x2 || typVars.typUarts[3].eRtsInt == eIntNone )
		{
			UCSR3B |= (unsigned char)BV(UDRIE3);
		}
		else
		{
			// Trigger Interrupt state
			int_trigger(typVars.typUarts[3].eRtsInt);
		}
	}
	else
	{
		UCSR3B &= (unsigned char)~(BV(UDRIE3));
	}
}
#endif
//-------------------------------------------------------------------------------------------

// Number of bytes to notify on
void			uart_bytes_rx	(uint8_t nUart,	u16 nBytes)
{
	typVars.typUarts[nUart].rxNotify = nBytes;
}

void	uart_send_byte			(uint8_t nUart, uint8_t data)
{
	// Append to buffer
	bufferAddToEnd(&typVars.typUarts[nUart].txBuffer, data);
	// Enable Tx
	enable_tx[nUart](1);
}

uint8_t		uart_send_buffer		(uint8_t nUart, unsigned char* buffer, u16 nBytes)
{
	bufferAddBufferToEndUnSafe(&typVars.typUarts[nUart].txBuffer, buffer, nBytes);
	// Enable Tx
	enable_tx[nUart](1);

	return 1;
}

void	uart_append_buffer_tx	(uint8_t nUart, unsigned char* buffer, u16 nBytes)
{
	bufferAddBufferToEndUnSafe(&typVars.typUarts[nUart].txBuffer, buffer, nBytes);
}

void	uart_flush_tx_buffer	(uint8_t nUart)
{
	bufferFlush(&typVars.typUarts[nUart].txBuffer);
	enable_tx[nUart](0);
}

void	uart_append_buffer_rx	(uint8_t nUart, unsigned char* buffer, u16 nBytes)
{
	if (typVars.typUarts[nUart].rxBytes + nBytes <= typVars.typUarts[nUart].rxLength)
	{
		// Copy into the buffer
		memcpy(&typVars.typUarts[nUart].rxBuf[typVars.typUarts[nUart].rxBytes]
			,buffer, nBytes);

		// Increment size
		typVars.typUarts[nUart].rxBytes += nBytes;

		// Notify listener if required to do so
		if (typVars.typUarts[nUart].rxBytes >= typVars.typUarts[nUart].rxNotify)
		{
			typVars.typUarts[nUart].uart_recieve(
				typVars.typUarts[nUart].rxBuf[typVars.typUarts[nUart].rxBytes]
				, typVars.typUarts[nUart].rxBytes);
		}
	}
}

void	uart_flush_rx_buffer	(uint8_t nUart)
{
	typVars.typUarts[nUart].rxBytes = 0;
}

void uart_set_baud(uint8_t nUart, u32 baudrate)
{
	// calculate division factor for requested baud rate, and set it
	uint8_t baudrateDiv;
	
	baudrateDiv = (uint8_t)((F_CPU+(baudrate*8L))/(baudrate*16L)-1);

	switch (nUart)
	{
	case 0:
		UBRR0L = baudrateDiv;
		break;
	case 1:
		UBRR1L = baudrateDiv;
		break;
#ifdef atmega1280
	case 2:
		UBRR2L = baudrateDiv;
		break;
	case 3:
		UBRR3L = baudrateDiv;
		break;
#endif
	}
}

__inline__ void	uart_recieve(uint8_t nUart, uint8_t c) 
{
	typVars.typUarts[nUart].rxBuf[typVars.typUarts[nUart].rxBytes++] = c;

	// Notify listener if required to do so
	if (typVars.typUarts[nUart].rxBytes >= typVars.typUarts[nUart].rxNotify)
	{
		typVars.typUarts[nUart].uart_recieve(c, typVars.typUarts[nUart].rxBytes);
	}
}

void	uart0_signal_rts	(unsigned char state)
{
	uart_enable_tx_0(state ? 2 : 0);
}

SIGNAL(SIG_USART0_DATA)
{
	UDR0 = bufferGetFromFront(&typVars.typUarts[0].txBuffer);

	uart_enable_tx_0(2);
}

SIGNAL(SIG_USART0_RECV)
{
	unsigned char c = inb(UDR0);
	typVars.typUarts[0].rxBuf[typVars.typUarts[0].rxBytes++] = c;

	// Notify listener if required to do so
	if (typVars.typUarts[0].rxBytes >= typVars.typUarts[0].rxNotify)
	{
		typVars.typUarts[0].uart_recieve(c, typVars.typUarts[0].rxBytes);
	}

//	uart_recieve(0, inb(UDR0));
}

void	uart1_signal_rts	(unsigned char state)
{
	uart_enable_tx_1(state ? 2 : 0 );
}

SIGNAL(SIG_USART1_DATA)
{
	UDR1 = bufferGetFromFront(&typVars.typUarts[1].txBuffer);

	uart_enable_tx_1(2);
}

SIGNAL(SIG_USART1_RECV)
{
	uart_recieve(1, inb(UDR1));
}

#if UART_COUNT > 2

void	uart2_signal_rts	(unsigned char state)
{
	uart_enable_tx_2(state ? 2 : 0 );
}

SIGNAL(SIG_USART2_DATA)
{
	UDR2 = bufferGetFromFront(&typVars.typUarts[2].txBuffer);

	uart_enable_tx_2(2);
}

SIGNAL(SIG_USART2_RECV)
{
	uart_recieve(2, inb(UDR2));
}

#endif

#if UART_COUNT > 3

void	uart3_signal_rts	(unsigned char state)
{
	uart_enable_tx_3(state ? 2 : 0 );
}

SIGNAL(SIG_USART3_DATA)
{
	UDR3 = bufferGetFromFront(&typVars.typUarts[3].txBuffer);

	uart_enable_tx_3(2);
}

SIGNAL(SIG_USART3_RECV)
{
	uart_recieve(3, inb(UDR3));
}

#endif
